package es.javamyadmin.dao;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;

import es.javamyadmin.modelo.Usuarios;
import es.javamyadmin.pojo.Mensaje;
import es.javamyadmin.pojo.Error;

/**
 * Clase con los distintos metodos para trabajar con los USUARIOS de MySQL.
 * @author Hector Delgado
 * @author Emilio Javier Castillo
 * @version 1.0
 */
public class UsuariosDAO {
	
	Connection conexion = null;
	Statement estamento = null;
	PreparedStatement preparada = null;
	ResultSet resultado = null;
	InputStream path = null;
	
	/**
	 * Metodo para leer los usuarios de MySQL.
	 * @param user String con el usuario para hacer la conexion a MySQL.
	 * @param pass String con el password para hacer la conexion a MySQL.
	 * @param host String con el servidor donde se encuentra MySQL.
	 * @param port String con el puerto del servidor de MySQL.
	 * @param clausulaWhere String con la clausula Where necesaria para la consulta.
	 * @return Una lista de objetos USUARIOS.
	 */
	public Collection<Usuarios> leerUsuarios(String user, String pass, String host, String port, String clausulaWhere){
		Collection<Usuarios> lista = new ArrayList<Usuarios>();
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
      	    
      	    String query = 	"SELECT "
      	    				+ " Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_Priv,"
      	    				+ " Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv,"
      	    				+ " References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv,"
      	    				+ " Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv, Create_view_priv,"
      	    				+ " Show_view_priv, Create_routine_priv, Alter_routine_priv, Create_user_priv, Event_priv,"
      	    				+ " Trigger_priv"
      	    				+ " FROM user "
      	    				+ 	clausulaWhere;
      	     
      	    PreparedStatement pstm = conexion.prepareStatement(query);
      	    resultado = pstm.executeQuery();
			while(resultado.next()){
				Usuarios usuarios = new Usuarios();
				usuarios.setUser(resultado.getString("User"));
				usuarios.setHost(resultado.getString("Host"));
				usuarios.setSelect_priv(resultado.getString("Select_priv"));
				usuarios.setInsert_priv(resultado.getString("Insert_priv"));
				usuarios.setUpdate_priv(resultado.getString("Update_priv"));
				usuarios.setDelete_priv(resultado.getString("Delete_priv"));
				usuarios.setCreate_priv(resultado.getString("Create_Priv"));
				usuarios.setDrop_priv(resultado.getString("Drop_priv"));
				usuarios.setReload_priv(resultado.getString("Reload_priv"));
				usuarios.setShutdown_priv(resultado.getString("Shutdown_priv"));
				usuarios.setProcess_priv(resultado.getString("Process_priv"));
				usuarios.setFile_priv(resultado.getString("File_priv"));
				usuarios.setGrant_priv(resultado.getString("Grant_priv"));
				usuarios.setReferences_priv(resultado.getString("References_priv"));
				usuarios.setIndex_priv(resultado.getString("Index_priv"));
				usuarios.setAlter_priv(resultado.getString("Alter_priv"));
				usuarios.setShow_db_priv(resultado.getString("Show_db_priv"));
				usuarios.setSuper_priv(resultado.getString("Super_priv"));
				usuarios.setCreate_tmp_table_priv(resultado.getString("Create_tmp_table_priv"));
				usuarios.setLock_tables_priv(resultado.getString("Lock_tables_priv"));
				usuarios.setExecute_priv(resultado.getString("Execute_priv"));
				usuarios.setRepl_slave_priv(resultado.getString("Repl_slave_priv"));
				usuarios.setRepl_client_priv(resultado.getString("Repl_client_priv"));
				usuarios.setCreate_view_priv(resultado.getString("Create_view_priv"));
				usuarios.setShow_view_priv(resultado.getString("Show_view_priv"));
				usuarios.setCreate_routine_priv(resultado.getString("Create_routine_priv"));
				usuarios.setAlter_routine_priv(resultado.getString("Alter_routine_priv"));
				usuarios.setCreate_user_priv(resultado.getString("Create_user_priv"));
				usuarios.setEvent_priv(resultado.getString("Event_priv"));
				usuarios.setTrigger_priv(resultado.getString("Trigger_priv"));
							
				lista.add(usuarios);				
			}
		} catch(SQLException | ClassNotFoundException ex){
			ex.printStackTrace();
		} finally {
			cerrarConexion();
		}
		
		return lista;		
	}
	
	/**
	 * Metodo para crear un nuevo Usuario de MySQL. 
	 * @param user String con el usuario para hacer la conexion a MySQL.
	 * @param pass String con el password para hacer la conexion a MySQL.
	 * @param host String con el servidor donde se encuentra MySQL.
	 * @param port String con el puerto del servidor de MySQL.
	 * @param usuario
	 * @return 
	 */
	public Error crearUsuario(String user, String pass, String host, String port, Usuarios usuario){
		
		Error error = null;
		String nameUsuario = usuario.getUser();
		String servidor = usuario.getHost();
		String password = usuario.getPassword();
		String bbdd = usuario.getBbdd();
		
		/*CREO EL NUEVO USUARIO*/
		try {
			Class.forName("com.mysql.jdbc.Driver");
      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
      	    
      	    String createUser = "CREATE USER '"+nameUsuario+"'@'"+servidor+"' IDENTIFIED BY  '"+password+"'";
      	    
      	    PreparedStatement pstm = conexion.prepareStatement(createUser);

      	    pstm.executeUpdate();
      	    
      	    
      	} catch(SQLException | ClassNotFoundException ex){
			ex.printStackTrace();
			error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), ""); 
		} finally {
			cerrarConexion();
		}
		
		/*SI NO HA HABIDO NINGUN ERROR LE DOY LOS PRIVILEGIOS ESPECIFICADOS AL USUARIO*/
		if(error == null & bbdd==null){
			
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String update = 	"UPDATE user set "
	    				+ 			" Select_priv=?, Insert_priv=?, Update_priv=?, Delete_priv=?, File_priv=?, Create_Priv=?, Alter_priv=?, Index_priv=?,"
	    				+ 			" Drop_priv=?, Create_tmp_table_priv=?, Show_view_priv=?, Create_routine_priv=?, Alter_routine_priv=?, Execute_priv=?,"
	    				+ 			" Create_view_priv=?, Event_priv=?, Trigger_priv=?, Grant_priv=?, Super_priv=?, Process_priv=?, Reload_priv=?, Shutdown_priv=?,"
	    				+ 			" Show_db_priv=?, Lock_tables_priv=?, References_priv=?, Repl_client_priv=?, Repl_slave_priv=?, Create_user_priv=?"
	    				+ 			" WHERE User=? AND Host=?";
	    
			    PreparedStatement pstm = conexion.prepareStatement(update);
			    
			    pstm.setString(1, usuario.getSelect_priv());
		    	pstm.setString(2, usuario.getInsert_priv());
		    	pstm.setString(3, usuario.getUpdate_priv());
		    	pstm.setString(4, usuario.getDelete_priv());
		    	pstm.setString(5, usuario.getFile_priv());
		    	pstm.setString(6, usuario.getCreate_priv());
		    	pstm.setString(7, usuario.getAlter_priv());
		    	pstm.setString(8, usuario.getIndex_priv());
		    	pstm.setString(9, usuario.getDrop_priv());
		    	pstm.setString(10, usuario.getCreate_tmp_table_priv());
		    	pstm.setString(11, usuario.getShow_view_priv());
		    	pstm.setString(12, usuario.getCreate_routine_priv());
		    	pstm.setString(13, usuario.getAlter_routine_priv());
		    	pstm.setString(14, usuario.getExecute_priv());
		    	pstm.setString(15, usuario.getCreate_view_priv());
		    	pstm.setString(16, usuario.getEvent_priv());
		    	pstm.setString(17, usuario.getTrigger_priv());
		    	pstm.setString(18, usuario.getGrant_priv());
		    	pstm.setString(19, usuario.getSuper_priv());
		    	pstm.setString(20, usuario.getProcess_priv());
		    	pstm.setString(21, usuario.getReload_priv());
		    	pstm.setString(22, usuario.getShutdown_priv());
		    	pstm.setString(23, usuario.getShow_db_priv());
		    	pstm.setString(24, usuario.getLock_tables_priv());
		    	pstm.setString(25, usuario.getReferences_priv());
		    	pstm.setString(26, usuario.getRepl_client_priv());
		    	pstm.setString(27, usuario.getRepl_slave_priv());
		    	pstm.setString(28, usuario.getCreate_user_priv());
		    	
		    	pstm.setString(29, usuario.getUser());
			    pstm.setString(30, usuario.getHost());
			    pstm.executeUpdate();
	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
				
			} finally {
				cerrarConexion();
			}
			
		}
		
		/*SI NO HA HABIDO NINGUN ERROR LE DOY LOS PRIVILEGIOS ESPECIFICADOS AL USUARIO SOBRE LA BASE DE DATOS*/
		if(error == null & bbdd!=null){
			
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String create = 	" INSERT INTO db "
	    				+ 			" (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_Priv, Drop_priv, Grant_priv, References_priv, Index_priv,"
	    				+ 			" Alter_priv, Create_tmp_table_priv, Lock_tables_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv,"
	    				+ 			" Event_priv, Trigger_priv)"
	    				+ 			" values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ";
	     
			    PreparedStatement pstm = conexion.prepareStatement(create);
			    			    
			    pstm.setString(1, usuario.getHost());
		    	pstm.setString(2, usuario.getBbdd());
		    	pstm.setString(3, usuario.getUser());
		    	pstm.setString(4, usuario.getSelect_priv());
		    	pstm.setString(5, usuario.getInsert_priv());
		    	pstm.setString(6, usuario.getUpdate_priv());
		    	pstm.setString(7, usuario.getDelete_priv());
		    	pstm.setString(8, usuario.getCreate_priv());
		    	pstm.setString(9, usuario.getDrop_priv());
		    	pstm.setString(10, usuario.getGrant_priv());
		    	pstm.setString(11, usuario.getReferences_priv());
		    	pstm.setString(12, usuario.getIndex_priv());
		    	pstm.setString(13, usuario.getAlter_priv());
		    	pstm.setString(14, usuario.getCreate_tmp_table_priv());
		    	pstm.setString(15, usuario.getLock_tables_priv());
		    	pstm.setString(16, usuario.getCreate_view_priv());
		    	pstm.setString(17, usuario.getShow_view_priv());
		    	pstm.setString(18, usuario.getCreate_routine_priv());
		    	pstm.setString(19, usuario.getAlter_routine_priv());
		    	pstm.setString(20, usuario.getExecute_priv());
		    	pstm.setString(21, usuario.getEvent_priv());
		    	pstm.setString(22, usuario.getTrigger_priv());
		    	
			    pstm.executeUpdate();
			    	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
				
			} finally {
				cerrarConexion();
			}
		
		}
						
		/*SI NO HA HABIDO NINGUN ERROR REFRESCO LOS PRIVILEGIOS*/
		if(error == null){
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String update = "FLUSH PRIVILEGES";
	      	     
	      	    PreparedStatement pstm = conexion.prepareStatement(update);
	      	    
	      	    pstm.executeUpdate();
	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,"5000"),((SQLException) ex).getMessage(), "");
				error.setWarning(true);
			} finally {
				cerrarConexion();
			}
		}
		
		return error;
	}
	
	/**
	 * Metodo para editar un Usuario de MySQL.
	 * @param user String con el usuario para hacer la conexion a MySQL.
	 * @param pass String con el password para hacer la conexion a MySQL.
	 * @param host String con el servidor donde se encuentra MySQL.
	 * @param port String con el puerto del servidor de MySQL.
	 * @param usuario
	 * @return
	 */
	public Error editarUsuario(String user, String pass, String host, String port, Usuarios usuario){
		
		Error error = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
      	    
      	    String update = 	"UPDATE user set "
      	    				+ 	" Select_priv=?, Insert_priv=?, Update_priv=?, Delete_priv=?, File_priv=?, Create_Priv=?, Alter_priv=?, Index_priv=?,"
      	    				+ 	" Drop_priv=?, Create_tmp_table_priv=?, Show_view_priv=?, Create_routine_priv=?, Alter_routine_priv=?, Execute_priv=?,"
      	    				+ 	" Create_view_priv=?, Event_priv=?, Trigger_priv=?, Grant_priv=?, Super_priv=?, Process_priv=?, Reload_priv=?, Shutdown_priv=?,"
      	    				+ 	" Show_db_priv=?, Lock_tables_priv=?, References_priv=?, Repl_client_priv=?, Repl_slave_priv=?, Create_user_priv=?"
      	    				+ 	" WHERE User=? AND Host=?";
      	     
      	    PreparedStatement pstm = conexion.prepareStatement(update);
      	    
      	    pstm.setString(1, usuario.getSelect_priv());
	      	pstm.setString(2, usuario.getInsert_priv());
	      	pstm.setString(3, usuario.getUpdate_priv());
	      	pstm.setString(4, usuario.getDelete_priv());
	      	pstm.setString(5, usuario.getFile_priv());
	      	pstm.setString(6, usuario.getCreate_priv());
	      	pstm.setString(7, usuario.getAlter_priv());
	      	pstm.setString(8, usuario.getIndex_priv());
	      	pstm.setString(9, usuario.getDrop_priv());
	      	pstm.setString(10, usuario.getCreate_tmp_table_priv());
	      	pstm.setString(11, usuario.getShow_view_priv());
	      	pstm.setString(12, usuario.getCreate_routine_priv());
	      	pstm.setString(13, usuario.getAlter_routine_priv());
	      	pstm.setString(14, usuario.getExecute_priv());
	      	pstm.setString(15, usuario.getCreate_view_priv());
	      	pstm.setString(16, usuario.getEvent_priv());
	      	pstm.setString(17, usuario.getTrigger_priv());
	      	pstm.setString(18, usuario.getGrant_priv());
	      	pstm.setString(19, usuario.getSuper_priv());
	      	pstm.setString(20, usuario.getProcess_priv());
	      	pstm.setString(21, usuario.getReload_priv());
	      	pstm.setString(22, usuario.getShutdown_priv());
	      	pstm.setString(23, usuario.getShow_db_priv());
	      	pstm.setString(24, usuario.getLock_tables_priv());
	      	pstm.setString(25, usuario.getReferences_priv());
	      	pstm.setString(26, usuario.getRepl_client_priv());
	      	pstm.setString(27, usuario.getRepl_slave_priv());
	      	pstm.setString(28, usuario.getCreate_user_priv());
	      	pstm.setString(29, usuario.getUser());
	      	pstm.setString(30, usuario.getHost());
	      	
      	    pstm.executeUpdate();
			
		} catch(SQLException | ClassNotFoundException ex){
			ex.printStackTrace();
			error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
		} finally {
			cerrarConexion();
		}
		
		if(error == null){
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String update = "FLUSH PRIVILEGES";
	      	     
	      	    PreparedStatement pstm = conexion.prepareStatement(update);
	      	    
	      	    pstm.executeUpdate();
	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,"5001"),((SQLException) ex).getMessage(), "");
				error.setWarning(true);
			} finally {
				cerrarConexion();
			}
		}
		
		return error;
	}
	
	/**
	 * Metodo para cambiar el Password de un Usuario de MySQL.
	 * @param user String con el usuario para hacer la conexion a MySQL.
	 * @param pass String con el password para hacer la conexion a MySQL.
	 * @param host String con el servidor donde se encuentra MySQL.
	 * @param port String con el puerto del servidor de MySQL.
	 * @param usuarioMod String con el Usuario a modifircar.
	 * @param hostMod String con el Servidor donde ha sido creado el Usuario.
	 * @param nuevoPass String con el nuevo Password.
	 * @return
	 */
	public Error editarPassUsuario(String user, String pass, String host, String port, String usuarioMod, String hostMod, String nuevoPass){
		
		Error error = null;
		
		/*Primero elimino lo privilegios*/
		try {
			Class.forName("com.mysql.jdbc.Driver");
      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
      	    
      	    String update = "SET PASSWORD FOR "+usuarioMod+"@"+hostMod+" = PASSWORD('"+nuevoPass+"')";
      	     
      	    PreparedStatement pstm = conexion.prepareStatement(update);
      	    
      	    pstm.executeUpdate();
      	    
      	} catch(SQLException | ClassNotFoundException ex){
			ex.printStackTrace();
			error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
		} finally {
			cerrarConexion();
		}
		
		return error;
	}
	
	/**
	 * Metodo para eliminar un Usuario de MySQL.
	 * @param user String con el usuario para hacer la conexion a MySQL.
	 * @param pass String con el password para hacer la conexion a MySQL.
	 * @param host String con el servidor donde se encuentra MySQL.
	 * @param port String con el puerto del servidor de MySQL.
	 * @param usuarioMod String con el Usuario a eliminar.
	 * @param hostMod String con el Servidor donde ha sido creado el Usuario. 
	 * @return
	 */
	public Error eliminarUsuario(String user, String pass, String host, String port, String usuarioMod, String hostMod){
				
		Error error = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
      	    
      	    String delete = "DELETE FROM user WHERE User='"+usuarioMod+"' AND Host='"+hostMod+"'";
      	     
      	    PreparedStatement pstm = conexion.prepareStatement(delete);
      	    
      	    pstm.executeUpdate();
      	    
      	} catch(SQLException | ClassNotFoundException ex){
			ex.printStackTrace();
			error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
		} finally {
			cerrarConexion();
		}
		
		/*Si no ha habido ningun error al BORRAR EL USUARIO, borro tambien los privilegios*/
		if(error == null){
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String deletePermisos = "DELETE FROM db WHERE User='"+usuarioMod+"' AND Host='"+hostMod+"'";
	      	     
	      	    PreparedStatement pstm = conexion.prepareStatement(deletePermisos);
	      	    
	      	    pstm.executeUpdate();
	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,String.valueOf(((SQLException) ex).getErrorCode())),((SQLException) ex).getMessage(), "");
			} finally {
				cerrarConexion();
			}
		}
		
		
		if(error == null){
			try {
				Class.forName("com.mysql.jdbc.Driver");
	      	    conexion=DriverManager.getConnection("jdbc:mysql://"+host+":"+port+"/mysql", user, pass);
	      	    
	      	    String update = "FLUSH PRIVILEGES";
	      	     
	      	    PreparedStatement pstm = conexion.prepareStatement(update);
	      	    
	      	    pstm.executeUpdate();
	      	    
	      	} catch(SQLException | ClassNotFoundException ex){
				ex.printStackTrace();
				error = new Error(Mensaje.getMensaje(path,"5002"),((SQLException) ex).getMessage(), "");
				error.setWarning(true);
	      	} finally {
				cerrarConexion();
			}
		}
		
		return error;
	}
	
	/**
	 * Metodo para cerrar la conexion.
	 */
	public void cerrarConexion(){
		if(resultado != null){
			try {
				resultado.close();
			} catch(SQLException e){
				e.printStackTrace();
			}
			resultado = null;
		}
		if(estamento != null){
			try {
				estamento.close();
			} catch(SQLException e){
				e.printStackTrace();
			}
			estamento = null;
		}
		if(preparada != null){
			try {
				preparada.close();
			} catch(SQLException e){
				e.printStackTrace();
			}
			preparada = null;
		}
		if(conexion != null){
			try {
				conexion.close();
			} catch(SQLException e){
				e.printStackTrace();
			}
			conexion = null;
		}
	}

	/**
	 * @return the path
	 */
	public InputStream getPath() {
		return path;
	}

	/**
	 * @param path the path to set
	 */
	public void setPath(InputStream path) {
		this.path = path;
	}
	
	
		
}
